Library Integration for IMU Example Application

From RidgeRun Developer Wiki

Follow Us On Twitter LinkedIn Email Share this page











Introduction

RidgeRun's Video Stabilization Library provides 2 example applications that serve as in-depth guides on how to use the library. This page explains the expected behavior and operation of these applications. In order to generate a stabilized video output, each application has to execute the integration, interpolation, and stabilization algorithms. The main difference between the examples is that one example works offline on externally provided sensor data and video footage. The other example works online with live video capture and sensor data acquisition.

Concept: Offline Video Stabilization with Gyroscopic Data

This application consists of two main parts: a preprocessing stage that emulates the inputs available in a real live feed and the main loop that captures frames and gyroscopic samples, as seen in the diagram below.

Block Diagram for Offline Example Application
Block Diagram for Offline Example Application

Next, a summary of the instances and stages is provided.

Instances

This application uses the following library components:

  • An Integrator with Integrator Settings.
  • An Interpolator with Interpolator Settings.
  • A Stabilizer with Stabilizer parameters.
  • A Fish Eye Undistort Instance with Null Parameters.

Preprocessing and Preparation

The input video will be downloaded from a remote link when building the project. At the same time, the gyro data is already included in the artifacts subdirectory for this project as a CSV file. The code will check that it is possible to:

  • Open the input video.
  • Open the gyro data file.
  • Create an "output.mp4" file for the final result.

For this example, the video properties, such as codec and frame rate, are extracted from the input file, although the output resolution is fixed to 640x480.

If the previous steps are successful, the program advances into the main loop, which treats each frame.

Main Operation Loop

This loop emulates how a live video would be processed, taking into account that data is available only from the current and past frames.

Pre-Integration

For each frame, there is an unknown number of gyro samples that match. Therefore, the first step is accumulating samples for the current time interval. If the remaining samples were insufficient to fill the interval, it will be considered the video's last frame.

Integration

The integrator transforms the samples into their corresponding timestamp-quaternion pair representation in an accumulation buffer.

Post-Integration

After integration, the timestamps are transposed due to the delay between the frame's capture and measurement.

Interpolation

The interpolator will check if the accumulated buffer has enough samples before interpolating. If not, the example will return to the integrator and extend the buffer. once the interpolation is done, the accumulated buffer is cleaned for the next integration.

Post-Interpolation

An interpolation buffer will take the first sample of the interpolated output, and the previous steps will repeat until there are three samples.

Stabilization

The 3-sized interpolation buffer is used to get a stabilized buffer of the same size. The middle values of the stabilized buffer and the interpolation buffer are used to estimate the correction rotation.

Image Transformation

To correct the image, the input and output frames must be allocated using the image allocator included in the library and the appropriate backend (this example employs OpenCV); and then an undistort instance transforms the image using the rotation obtained from the stabilization step. Finally, the frame is written into the output video.

Additional Details

The application is constructed by default by the building system. Make sure to have -Denable-examples=enabled in the construction.

First, download the video and the raw gyro data using:

wget "https://drive.usercontent.google.com/download?id=1uW2sg3E2W2UOF9rjDaHG8eJus7m531_4&export=download&authuser=0&confirm=f" -O test-video-reencoded.mp4

wget "https://drive.usercontent.google.com/download?id=1LXjqut2c8YIiJg66vH_UyYSdP664OErw&export=download&authuser=0&confirm=f" -O raw-gyro-data.csv

To execute, simply:

BUILDDIR=builddir
./${BUILDDIR}/examples/concept/rvs-complete-concept -f test-video-reencoded.mp4 -g raw-gyro-data.csv -b opencv

For more options:

Usage:                                                     
    rvs-complete-offline-concept [-n NUMBER_OF_FRAMES] [-f INPUT_VIDEO] [-g GYRO_DATA] [-o OUTPUT_VIDEO] [-b BACKEND] [-w WIDTH] [-h HEIGHT] [-s FIELD_OF_VIEW_SCALE]      

Options:                                                   
    --help: prints this message                            
    -g: raw gyro data in CSV                               
    -f: input video file to stabilise                      
    -o: output video file stabilised. Def: output.mp4      
    -b: backend. Options: opencv (def), opencl, cuda       
    -n: number of frames to stabilise                      
    -w: output width (def: 1280)                            
    -h: output height (def: 720)                           
    -s: field of view scale (def: 2.4)  

With this, it is possible to change the location of the files, select a backend, and modify the output resolution for performance testing. The camera matrix is set by default, and it may not lead to the most optimal results. Moreover, the higher the resolution, you may need to lower the field of view scale (-s) to zoom over the image.

If you are looking to compile your application and use our library, you can compile this example using:

RAW_GYRO_FILE=FULL_PATH_TO_RAW_GYRO
VIDEO_FILE=FULL_PATH_TO_VIDEO
g++ -o concept complete-code-example.cpp $(pkg-config rvs --cflags --libs) -DRAW_GYRO_INPUT_FILE=${RAW_GYRO_FILE} -DTEST_VIDEO=${VIDEO_FILE}


Concept: Online Video Stabilization with Live Video Capture and Sensor Data Acquisition

This application makes use of the Gstreamer C API directly to provide performant video capture, video writing, and event loop handling. In order to separate these tasks from the RVS stabilization steps, this application defines 2 general classes: A GstreamerManager and a StabilizationManager. The following sections dive into more detail on the processing steps of both classes.

The GstreamerManager

Here is a diagram that lays out the data flow of the main stages within the GstreamerManager:

Block Diagram for GstreamerManager
Block Diagram for GstreamerManager


The GstreamerManager sets up an input pipeline that captures frames and metadata from the camera and delivers this data to an app sink. The app sink then invokes a callback upon receiving new camera data, which is where the StabilizationManager can work its magic on the camera data to produce a stabilized output. Finally this stabilized output is pushed onto the app source of an output pipeline, which then saves the output to a file.

The Input Pipeline

On the diagram above, some elements of the input pipeline are removed in order to focus on the main steps. However, it is important that the input pipeline can use the rrv4l2src element to be able to read camera Start of Frame (SOF) timestamps (more on how to build this element here). Also, the input pipeline can handle both raw input and MJPEG input, which it then converts to RGBA. Finally, the input pipeline uses a tee to send the data to an app sink and to save the camera capture to an unstabilized output file as a H264 codified MP4 file. This file can be used as a reference to compare against the stabilized output.

OnNewSample Callback

Once new camera data reaches the input pipeline app sink, it emits a new-sample signal, which then calls on the OnNewSample callback. This callback then receives the Gstreamer Sample, where it can extract both the frame buffer and the SOF timestamp from the sample metadata. The GstreamerManager then invokes the StabilizationManager StabilizeFrame method on the frame buffer and SOF timestamp, which results in a stabilized output frame buffer. Finally, the callback packages the output frame buffer into a Gstreamer sample and emits the push-sample signal to send this sample to the app source on the output pipeline.

Output Pipeline

This pipeline receives buffers through its app source, sent from the OnNewSample callback. This pipeline then saves the buffers to a stabilized output file using a H264 encoded MP4 file.

The StabilizationManager

Here is a diagram that illustrates the basic processing stages of the StabilizationManager:

Block Diagram for StabilizationManager
Block Diagram for StabilizationManager


The StabilizationManager runs a thread that focuses on reading from the IMU sensor and pushing the sensor payloads to a queue. In parallel, when the GstreamerManager receives a new frame from the camera, it invokes the StabilizeFrame method of the StabilizationManager. Here is where the RVS library components are used to produce a stabilized output frame.

Sensor Thread

This thread makes use of a RVS ISensor instance to extract sensor payloads, containing gyroscope, accelerometer, and timestamp data. These payloads are pushed to a queue and then the sensor thread sleeps in order to regulate the sensor sampling rate. If the queue reaches a maximum size, then old payloads are dropped. This queue is read from the main loop when executing the StabilizeFrame stage and then the queue is cleared. The sensor thread is expected to run at a higher frequency than the frame stabilization rate, meaning that for each frame iteration, there should be multiple sensor payloads in the queue.

Stabilize Frame

The StabilizeFrame stage runs the main RVS steps, which are explained in detailed here. To quickly summarize, the first step in stabilizing the image is to determine the camera orientation at the time that the capture was taken. The IMU gyroscope data is the main way of determining camera orientations, but this data comes in the form of angular velocities. The Integrate step obtains concrete orientations from angular velocity data. The sensor data will probably not synchronize precisely with the moment that the camera capture is taken, so the Interpolate step determines the likely camera orientation at capture time from the integrated sensor data; this is where the SOF timestamp is used. Once the orientation of the camera at capture time is determined, the Stabilize step finds the necessary rotation to correct the input image movement. Finally, the Undistort step is able to apply corrections to the input image based on the stabilization rotation and the camera calibration matrices in order to produce a stabilized output.

Additional Details

Similar to the offline example application, this application is constructed by default by the building system. Make sure to have -Denable-examples=enabled in the construction. Additionally, this example requires OpenCV, CUDA, and Gstreamer support, during construction these are enabled with -Denable-opencv=enabled -Denabled-cuda=enabled -Denable-gstreamer=enabled.

Here is an example of the usage with every option specified:

rvs-complete-online-concept --help --width 1920 --height 1080 --framerate 30/1 --sensor-name Icm42600 --sensor-device icm42688 --sensor-frequency 200 --sensor-orientation xYz --smoothing-constant 0.3 --field-of-view 1.2 --calibration-file calibration.yml --backend CUDA --unstabilized-output unstabilized_output.mp4 --stabilized-output stabilized_output.mp4 --video-format MJPG --video-device /dev/video0

Here is the complete usage message:

Usage:                                                     
    rvs-complete-online-concept [--width WIDTH] [--height HEIGHT] [--framerate FRAMERATE] [--sensor-name SENSOR_NAME] [--sensor-device SENSOR_DEVICE] [--sensor-frequency SENSOR_FREQUENCY] [--sensor-orientation SENSOR_ORIENTATION] [--smoothing-constant SMOOTHING_CONSTANT] [--field-of-view FIELD_OF_VIEW] [--calibration-file CALIBRATION_FILE] [--backend BACKEND] [--unstabilized-output OUTPUT] [--stabilized-output STABILIZED_OUTPUT] [--video-format VIDEO_FORMAT] [--video-device VIDEO_DEVICE]     

Options:                                                   
    --help: prints this message                            
    --width: input/output video width                      
        default: 1920
    --height: input/output video height                    
        default: 1080
    --framerate: input/output video framerate              
        default: 30/1
    --sensor-name: sensor name to use for IMU data         
        default: Bmi160
    --sensor-device: sensor device to use for IMU data     
        default: /dev/i2c-7
    --sensor-frequency: sensor sampling frequency          
        default: 300
    --sensor-orientation: IMU to camera orientation        
        default: xzy
    --smoothing-constant: stabilization smoothing constant 
        default: 0.2
    --field-of-view: undistort field of view               
        default: 1.5
    --calibration-file: file with camera lens calibration  
        default: calibration.yml
    --backend: undistortion algorithm backend              
        default: CUDA
    --unstabilized-output: path to unstabilized output     
        default: unstabilized_output.mp4
    --stabilized-output: path to stabilized output         
        default: stabilized_output.mp4
    --video-format: format for capture ('MJPG' or 'RAW')   
        default: MJPG
    --video-device: device for capture                     
        default: /dev/video0